// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, kearn.chen@aliyun.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
//             1. Control and Status Register
// -------------------------------------------------------------------------------------------------

module k0a_core_csr (
    input  wire         core_clk         ,
    input  wire         core_rstn        ,

    input  wire         idu2csr_we       ,
    input  wire [11:0]  idu2csr_addr     ,
    input  wire [31:0]  idu2csr_wdata    ,
    output wire [31:0]  csr2idu_rdata    ,

    output reg          csr2cic_gie      ,
    output reg  [15:0]  csr2cic_mie      ,
    output reg  [15:0]  csr2cic_mip      ,
    input  wire [15:0]  cic2csr_irq      ,
    input  wire [4:0]   cic2csr_mcause   ,

    output reg  [17:0]  csr2idu_mepc     ,
    output reg  [17:0]  csr2idu_mtvec    ,
    input  wire         idu2csr_mepc_set ,
    input  wire [17:0]  idu2csr_mepc_nxt
);

localparam CSR_MARCHID  = 12'hf12;
localparam CSR_MSTATUS  = 12'h300;
localparam CSR_MISA     = 12'h301;
localparam CSR_MIE      = 12'h304;
localparam CSR_MTVEC    = 12'h305;
localparam CSR_MEPC     = 12'h341;
localparam CSR_MCAUSE   = 12'h342;
localparam CSR_MIP      = 12'h344;

wire csr_marchid_sel  = idu2csr_addr == CSR_MARCHID;
wire csr_mstatus_sel  = idu2csr_addr == CSR_MSTATUS;
wire csr_misa_sel     = idu2csr_addr == CSR_MISA;
wire csr_mie_sel      = idu2csr_addr == CSR_MIE;
wire csr_mtvec_sel    = idu2csr_addr == CSR_MTVEC;
wire csr_mepc_sel     = idu2csr_addr == CSR_MEPC;
wire csr_mcause_sel   = idu2csr_addr == CSR_MCAUSE;
wire csr_mip_sel      = idu2csr_addr == CSR_MIP;

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        csr2cic_gie <= 1'b0;
    else if(csr_mstatus_sel & idu2csr_we)
        csr2cic_gie <= idu2csr_wdata[3];
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn) begin
        csr2cic_mie <= 16'd0;
    end else if(csr_mie_sel & idu2csr_we)
        csr2cic_mie <= idu2csr_wdata[15:0];
end

always @(posedge core_clk)
begin
    if(csr_mtvec_sel & idu2csr_we)
        csr2idu_mtvec <= idu2csr_wdata[19:2];
end

always @(posedge core_clk)
begin
    if(idu2csr_mepc_set)
        csr2idu_mepc <= idu2csr_mepc_nxt;
    else if(csr_mepc_sel & idu2csr_we)
        csr2idu_mepc <= idu2csr_wdata[19:2];
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        csr2cic_mip <= 16'd0;
    else if(csr_mip_sel & idu2csr_we)
        csr2cic_mip <= idu2csr_wdata[15:0] | cic2csr_irq;
    else if(csr2cic_gie)
        csr2cic_mip <= csr2cic_mip | cic2csr_irq;
end

assign csr2idu_rdata = {32{csr_marchid_sel  }} & 32'h4b2d3041                                    |
                       {32{csr_mstatus_sel  }} & {28'h180, csr2cic_gie, 3'd0}                    |
                       {32{csr_misa_sel     }} & 32'h40000010                                    |
                       {32{csr_mie_sel      }} & {16'd0, csr2cic_mie}                            |
                       {32{csr_mtvec_sel    }} & {12'd0, csr2idu_mtvec, 2'd0}                    |
                       {32{csr_mepc_sel     }} & {12'd0, csr2idu_mepc, 2'd0}                     |
                       {32{csr_mcause_sel   }} & {cic2csr_mcause[4], 27'd0, cic2csr_mcause[3:0]} |
                       {32{csr_mip_sel      }} & {16'd0, csr2cic_mip}                            ;

endmodule
